package com.snail.common.excel.handler;

import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentLoopMerge;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.annotation.write.style.HeadStyle;
import com.alibaba.excel.metadata.CellRange;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.property.ColumnWidthProperty;
import com.alibaba.excel.metadata.property.FontProperty;
import com.alibaba.excel.metadata.property.LoopMergeProperty;
import com.alibaba.excel.metadata.property.StyleProperty;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.alibaba.excel.write.property.ExcelWriteHeadProperty;
import com.snail.common.excel.annotation.Excel;
import org.apache.poi.ss.usermodel.Font;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @Description: Sheet write ExcelHandler
 * @Author: Snail
 * @CreateDate: 2023/8/17 8:48
 * @Version: V1.0
 */
public class SnailSheetWriteHandler implements SheetWriteHandler {

    /**
     * 是否导出模板
     */
    private final Boolean template;

    public SnailSheetWriteHandler(Boolean template) {
        this.template = template;
    }


    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Map<Integer, Head> map = writeWorkbookHolder.getExcelWriteHeadProperty().getHeadMap();
        Map<String, Integer> sortMap = new HashMap<>();
        map.forEach((k, v) -> {
            sortMap.put(v.getFieldName(), k);
        });
        //设置Excel表头
        Map<Integer, Head> headMap = new HashMap<>(64);
        Class<?> clazz = writeSheetHolder.getClazz();
        //获取类的注解
        ColumnWidth parentColumnWidth = clazz.getAnnotation(ColumnWidth.class);
        HeadStyle parentHeadStyle = clazz.getAnnotation(HeadStyle.class);
        HeadFontStyle parentHeadFontStyle = clazz.getAnnotation(HeadFontStyle.class);
        int headRowNumber = setHeadMap(clazz, headMap, sortMap, parentColumnWidth, parentHeadStyle, parentHeadFontStyle);
        ExcelWriteHeadProperty excelWriteHeadProperty = writeSheetHolder.getExcelWriteHeadProperty();
        excelWriteHeadProperty.setHeadRowNumber(headRowNumber);
        excelWriteHeadProperty.setHeadMap(headMap);
        writeSheetHolder.setExcelWriteHeadProperty(excelWriteHeadProperty);
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    }

    /**
     * 遍历属性有Excel注解的属性加入表头
     *
     * @param clazz               类
     * @param headMap             标题
     * @param sortMap             默认字段排序
     * @param parentColumnWidth   类的宽度
     * @param parentHeadStyle     类的样式
     * @param parentHeadFontStyle 类的字体样式
     */
    private int setHeadMap(Class<?> clazz,
                            Map<Integer, Head> headMap,
                            Map<String, Integer> sortMap,
                            ColumnWidth parentColumnWidth,
                            HeadStyle parentHeadStyle,
                            HeadFontStyle parentHeadFontStyle) {
        int headRowNumber = 1;
        //属性
        Field[] fields = clazz.getDeclaredFields();
        //获取
        for (Field field : fields) {
            Excel excel = field.getAnnotation(Excel.class);
            //没有Excel注解
            if (excel == null) {
                continue;
            }
            //是否导出模板
            if (template && !excel.template()) {
                continue;
            }
            String fieldName = field.getName();
            String[] fieldDesc = excel.value() == null ? new String[]{fieldName} : excel.value();
            headRowNumber = Math.max(fieldDesc.length,headRowNumber);
            //默认排序
            Integer sort = sortMap.get(fieldName);
            int index = getNewKey(headMap, excel.index());
            //默认排序和指定排序不相等
            if (index != sort) {
                //将默认排序中的数据进行交换
                sortMap.put(fieldName, index);
                //获取index对应的value
                Optional<String> optional = sortMap.keySet().stream().filter(key -> sortMap.get(key) == index).findFirst();
                optional.ifPresent(s -> sortMap.put(s, sort));
            }
            Head head = new Head(index, field, fieldName, Arrays.asList(fieldDesc), Boolean.TRUE, Boolean.TRUE);

            ColumnWidth columnWidth = field.getAnnotation(ColumnWidth.class);
            if (columnWidth == null) {
                columnWidth = parentColumnWidth;
            }
            head.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth));

            HeadStyle headStyle = field.getAnnotation(HeadStyle.class);
            if (headStyle == null) {
                headStyle = parentHeadStyle;
            }
            head.setHeadStyleProperty(StyleProperty.build(headStyle));
            HeadFontStyle headFontStyle = field.getAnnotation(HeadFontStyle.class);
            if (parentHeadFontStyle == null && headFontStyle == null) {
                FontProperty fontProperty = new FontProperty();
                fontProperty.setColor(Font.COLOR_NORMAL);
                head.setHeadFontProperty(fontProperty);
            } else if (headFontStyle == null) {
                head.setHeadFontProperty(FontProperty.build(parentHeadFontStyle));
            }else{
                head.setHeadFontProperty(FontProperty.build(headFontStyle));
            }
            head.setLoopMergeProperty(LoopMergeProperty.build(field.getAnnotation(ContentLoopMerge.class)));
            headMap.put(index, head);
        }
        //父类
        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            setHeadMap(superclass, headMap, sortMap, parentColumnWidth, parentHeadStyle, parentHeadFontStyle);
        }
        return headRowNumber;
    }

    /**
     * @param headMap 标题headMap
     * @param index   排序
     * @return 结果
     */
    private int getNewKey(Map<Integer, Head> headMap, int index) {
        //指定排序的最大值
        int max = headMap.keySet().stream().max(Integer::compareTo).orElse(-1);
        index = index == -1 ? max + 1 : index;
        //index是否在headMap中存在
        Head head = headMap.get(index);
        if (head == null) {
            return index;
        }
        //如果指定排序为存在的放在最后
        headMap.put(max + 1, head);
        return index;
    }
}
